home *** CD-ROM | disk | FTP | other *** search
- //------------------------------------------------------------------------------
- // File: JukeboxDlg.cpp
- //
- // Desc: DirectShow sample code - implementation of CJukeboxDlg class.
- //
- // Copyright (c) 1998-2001 Microsoft Corporation. All rights reserved.
- //------------------------------------------------------------------------------
-
- #include "stdafx.h"
- #include <atlbase.h>
- #include "Jukebox.h"
- #include "JukeboxDlg.h"
- #include "playvideo.h"
- #include "mediatypes.h"
-
- #ifdef _DEBUG
- #define new DEBUG_NEW
- #undef THIS_FILE
- static char THIS_FILE[] = __FILE__;
- #endif
-
- /////////////////////////////////////////////////////////////////////////////
- // CAboutDlg dialog used for App About
-
- class CAboutDlg : public CDialog
- {
- public:
- CAboutDlg();
-
- // Dialog Data
- //{{AFX_DATA(CAboutDlg)
- enum { IDD = IDD_ABOUTBOX };
- //}}AFX_DATA
-
- // ClassWizard generated virtual function overrides
- //{{AFX_VIRTUAL(CAboutDlg)
- protected:
- virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
- //}}AFX_VIRTUAL
-
- // Implementation
- protected:
- //{{AFX_MSG(CAboutDlg)
- //}}AFX_MSG
- DECLARE_MESSAGE_MAP()
- };
-
- CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
- {
- //{{AFX_DATA_INIT(CAboutDlg)
- //}}AFX_DATA_INIT
- }
-
- void CAboutDlg::DoDataExchange(CDataExchange* pDX)
- {
- CDialog::DoDataExchange(pDX);
- //{{AFX_DATA_MAP(CAboutDlg)
- //}}AFX_DATA_MAP
- }
-
- BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
- //{{AFX_MSG_MAP(CAboutDlg)
- // No message handlers
- //}}AFX_MSG_MAP
- END_MESSAGE_MAP()
-
- /////////////////////////////////////////////////////////////////////////////
- // CJukeboxDlg dialog
-
- CJukeboxDlg::CJukeboxDlg(CWnd* pParent /*=NULL*/)
- : CDialog(CJukeboxDlg::IDD, pParent)
- {
- //{{AFX_DATA_INIT(CJukeboxDlg)
- //}}AFX_DATA_INIT
- // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
- m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
- }
-
- void CJukeboxDlg::DoDataExchange(CDataExchange* pDX)
- {
- CDialog::DoDataExchange(pDX);
- //{{AFX_DATA_MAP(CJukeboxDlg)
- DDX_Control(pDX, IDC_STATIC_POSITION, m_StrPosition);
- DDX_Control(pDX, IDC_SLIDER, m_Seekbar);
- DDX_Control(pDX, IDC_STATIC_IMAGESIZE, m_StrImageSize);
- DDX_Control(pDX, IDC_STATIC_DURATION, m_StrDuration);
- DDX_Control(pDX, IDC_EDIT_MEDIADIR, m_EditMediaDir);
- DDX_Control(pDX, IDC_SPIN_FILES, m_SpinFiles);
- DDX_Control(pDX, IDC_BUTTON_FRAMESTEP, m_ButtonFrameStep);
- DDX_Control(pDX, IDC_LIST_EVENTS, m_ListEvents);
- DDX_Control(pDX, IDC_CHECK_EVENTS, m_CheckEvents);
- DDX_Control(pDX, IDC_BUTTON_PROPPAGE, m_ButtonProperties);
- DDX_Control(pDX, IDC_STATUS_DIRECTORY, m_StrMediaPath);
- DDX_Control(pDX, IDC_CHECK_MUTE, m_CheckMute);
- DDX_Control(pDX, IDC_BUTTON_STOP, m_ButtonStop);
- DDX_Control(pDX, IDC_BUTTON_PLAY, m_ButtonPlay);
- DDX_Control(pDX, IDC_BUTTON_PAUSE, m_ButtonPause);
- DDX_Control(pDX, IDC_CHECK_PLAYTHROUGH, m_CheckPlaythrough);
- DDX_Control(pDX, IDC_CHECK_LOOP, m_CheckLoop);
- DDX_Control(pDX, IDC_STATIC_FILEDATE, m_StrFileDate);
- DDX_Control(pDX, IDC_STATIC_FILESIZE, m_StrFileSize);
- DDX_Control(pDX, IDC_LIST_PINS_OUTPUT, m_ListPinsOutput);
- DDX_Control(pDX, IDC_LIST_PINS_INPUT, m_ListPinsInput);
- DDX_Control(pDX, IDC_STATIC_FILELIST, m_StrFileList);
- DDX_Control(pDX, IDC_STATUS, m_Status);
- DDX_Control(pDX, IDC_MOVIE_SCREEN, m_Screen);
- DDX_Control(pDX, IDC_LIST_FILTERS, m_ListFilters);
- DDX_Control(pDX, IDC_LIST_FILES, m_ListFiles);
- //}}AFX_DATA_MAP
- }
-
- BEGIN_MESSAGE_MAP(CJukeboxDlg, CDialog)
- //{{AFX_MSG_MAP(CJukeboxDlg)
- ON_WM_ERASEBKGND()
- ON_WM_SYSCOMMAND()
- ON_WM_PAINT()
- ON_WM_QUERYDRAGICON()
- ON_WM_CLOSE()
- ON_WM_DESTROY()
- ON_LBN_SELCHANGE(IDC_LIST_FILES, OnSelectFile)
- ON_BN_CLICKED(IDC_BUTTON_PAUSE, OnPause)
- ON_BN_CLICKED(IDC_BUTTON_PLAY, OnPlay)
- ON_BN_CLICKED(IDC_BUTTON_STOP, OnStop)
- ON_BN_CLICKED(IDC_CHECK_MUTE, OnCheckMute)
- ON_BN_CLICKED(IDC_CHECK_LOOP, OnCheckLoop)
- ON_BN_CLICKED(IDC_CHECK_PLAYTHROUGH, OnCheckPlaythrough)
- ON_LBN_SELCHANGE(IDC_LIST_FILTERS, OnSelchangeListFilters)
- ON_LBN_DBLCLK(IDC_LIST_FILTERS, OnDblclkListFilters)
- ON_BN_CLICKED(IDC_BUTTON_PROPPAGE, OnButtonProppage)
- ON_BN_CLICKED(IDC_CHECK_EVENTS, OnCheckEvents)
- ON_BN_CLICKED(IDC_BUTTON_FRAMESTEP, OnButtonFramestep)
- ON_BN_CLICKED(IDC_BUTTON_CLEAR_EVENTS, OnButtonClearEvents)
- ON_LBN_DBLCLK(IDC_LIST_FILES, OnDblclkListFiles)
- ON_NOTIFY(UDN_DELTAPOS, IDC_SPIN_FILES, OnDeltaposSpinFiles)
- ON_BN_CLICKED(IDC_BUTTON_SET_MEDIADIR, OnButtonSetMediadir)
- ON_WM_TIMER()
- ON_BN_CLICKED(IDC_BUTTON_GRAPHEDIT, OnButtonGraphedit)
- //}}AFX_MSG_MAP
- END_MESSAGE_MAP()
-
-
- /////////////////////////////////////////////////////////////////////////////
- // CJukeboxDlg message handlers
-
- void CJukeboxDlg::OnSysCommand(UINT nID, LPARAM lParam)
- {
- if ((nID & 0xFFF0) == IDM_ABOUTBOX)
- {
- CAboutDlg dlgAbout;
- dlgAbout.DoModal();
- }
- else
- {
- CDialog::OnSysCommand(nID, lParam);
- }
- }
-
- // If you add a minimize button to your dialog, you will need the code below
- // to draw the icon. For MFC applications using the document/view model,
- // this is automatically done for you by the framework.
-
- void CJukeboxDlg::OnPaint()
- {
- if (IsIconic())
- {
- CPaintDC dc(this); // device context for painting
-
- SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
-
- // Center icon in client rectangle
- int cxIcon = GetSystemMetrics(SM_CXICON);
- int cyIcon = GetSystemMetrics(SM_CYICON);
- CRect rect;
- GetClientRect(&rect);
- int x = (rect.Width() - cxIcon + 1) / 2;
- int y = (rect.Height() - cyIcon + 1) / 2;
-
- // Draw the icon
- dc.DrawIcon(x, y, m_hIcon);
- }
- else
- {
- CDialog::OnPaint();
- }
- }
-
- // The system calls this to obtain the cursor to display while the user drags
- // the minimized window.
- HCURSOR CJukeboxDlg::OnQueryDragIcon()
- {
- return (HCURSOR) m_hIcon;
- }
-
-
- /////////////////////////////////////////////////////////////////////////////
- // CJukeboxDlg DirectShow code and message handlers
-
-
- BOOL CJukeboxDlg::OnInitDialog()
- {
- CDialog::OnInitDialog();
-
- // Add "About..." menu item to system menu.
-
- // IDM_ABOUTBOX must be in the system command range.
- ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
- ASSERT(IDM_ABOUTBOX < 0xF000);
-
- CMenu* pSysMenu = GetSystemMenu(FALSE);
- if (pSysMenu != NULL)
- {
- CString strAboutMenu;
- strAboutMenu.LoadString(IDS_ABOUTBOX);
- if (!strAboutMenu.IsEmpty())
- {
- pSysMenu->AppendMenu(MF_SEPARATOR);
- pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
- }
- }
-
- // Set the icon for this dialog. The framework does this automatically
- // when the application's main window is not a dialog
- SetIcon(m_hIcon, TRUE); // Set big icon
- SetIcon(m_hIcon, FALSE); // Set small icon
-
- // Initialize COM
- CoInitialize(NULL);
-
- // Initialize DirectShow and query for needed interfaces
- HRESULT hr = InitDirectShow();
- if(FAILED(hr))
- {
- RetailOutput(TEXT("Failed to initialize DirectShow! hr=0x%x\r\n"), hr);
- return FALSE;
- }
-
- // IMPORTANT
- // Since we're embedding video in a child window of a dialog,
- // we must set the WS_CLIPCHILDREN style to prevent the bounding
- // rectangle from drawing over our video frames.
- //
- // Neglecting to set this style can lead to situations when the video
- // is erased and replaced with black (or the default color of the
- // bounding rectangle).
- m_Screen.ModifyStyle(0, WS_CLIPCHILDREN);
-
- // Propagate the files list and select the first item
- InitMediaDirectory();
-
- // Initialize seeking trackbar range
- m_Seekbar.SetRange(0, 100, TRUE);
- m_Seekbar.SetTicFreq(10);
-
- return TRUE; // return TRUE unless you set the focus to a control
- }
-
-
- void CJukeboxDlg::InitMediaDirectory(void)
- {
- // Fill the media file list, starting with the directory passed
- // on the command line. If no directory is passed, then read the
- // default media path for the DirectX SDK.
- TCHAR szDir[MAX_PATH];
- LONG lResult=0;
-
- if (theApp.m_lpCmdLine[0] == L'\0')
- {
- lResult = GetDXMediaPath(szDir);
-
- // If the DirectX SDK is not installed, use the Windows media
- // directory instead.
- if (lResult != 0)
- {
- GetWindowsDirectory(szDir, MAX_PATH);
- _tcscat(szDir, _T("\\Media\\") );
- }
- }
- else
- _tcscpy(szDir, theApp.m_lpCmdLine);
-
- TCHAR szPathMsg[MAX_PATH];
- wsprintf(szPathMsg, TEXT("Media directory: %s\0"), szDir);
- m_StrMediaPath.SetWindowText(szPathMsg);
-
- // Save current directory name
- wsprintf(m_szCurrentDir, TEXT("%s\0"), szDir);
-
- m_EditMediaDir.SetLimitText(MAX_PATH);
- m_EditMediaDir.SetWindowText(szDir);
-
- // Find all files in this directory and fill the list box
- FillFileList(szDir);
- }
-
-
- LONG CJukeboxDlg::GetDXMediaPath(TCHAR *szPath)
- {
- HKEY hKey;
- DWORD dwType, dwSize = MAX_PATH;
-
- // Open the appropriate registry key
- LONG lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
- _T("Software\\Microsoft\\DirectX SDK"),
- 0, KEY_READ, &hKey );
- if( ERROR_SUCCESS != lResult )
- return -1;
-
- lResult = RegQueryValueEx( hKey, _T("DX81SDK Samples Path"), NULL,
- &dwType, (BYTE*)szPath, &dwSize );
- RegCloseKey( hKey );
-
- if( ERROR_SUCCESS != lResult )
- return -1;
-
- _tcscat( szPath, _T("\\Media\\") );
- return 0;
- }
-
-
- void CJukeboxDlg::FillFileList(LPTSTR pszRootDir)
- {
- UINT attr = 0;
-
- m_ListFiles.ResetContent();
-
- ::SetCurrentDirectory(pszRootDir);
- Say(TEXT("Building file list..."));
-
- // Add all of our known supported media types to the file list.
- // Add files of each type in order.
- for (int i=0; i < NUM_MEDIA_TYPES; i++)
- {
- m_ListFiles.Dir(attr, TypeInfo[i].pszType);
- }
- Say(TEXT("File list complete."));
-
- // Update list box title with number of items added
- int nItems = m_ListFiles.GetCount();
- TCHAR szTitle[64];
- wsprintf(szTitle, TEXT("Media files (%d found)"), nItems);
- m_StrFileList.SetWindowText(szTitle);
-
- // Automatically select the first file in the list once
- // the dialog is displayed.
- PostMessage(WM_FIRSTFILE, 0, 0L);
- m_nCurrentFileSelection = -1; // No selection yet
- }
-
-
- void CJukeboxDlg::OnClose()
- {
- // Release DirectShow interfaces
- StopMedia();
- FreeDirectShow();
-
- // Release COM
- CoUninitialize();
-
- CDialog::OnClose();
- }
-
- void CJukeboxDlg::OnDestroy()
- {
- FreeDirectShow();
-
- CDialog::OnDestroy();
- }
-
-
- void CJukeboxDlg::OnSelectFile()
- {
- HRESULT hr;
- TCHAR szFilename[MAX_PATH];
-
- // If this is the currently selected file, do nothing
- int nItem = m_ListFiles.GetCurSel();
- if (nItem == m_nCurrentFileSelection)
- return;
-
- // Remember the current selection to speed double-click processing
- m_nCurrentFileSelection = nItem;
-
- // Read file name from list box
- m_ListFiles.GetText(nItem, szFilename);
-
- // Remember current play state to restart playback
- int nCurrentState = g_psCurrent;
-
- // First release any existing interfaces
- ResetDirectShow();
-
- // Clear filter/pin/event information listboxes
- m_ListFilters.ResetContent();
- m_ListPinsInput.ResetContent();
- m_ListPinsOutput.ResetContent();
- m_ListEvents.ResetContent();
-
- // Load the selected media file
- hr = PrepareMedia(szFilename);
- if (FAILED(hr))
- {
- // Error - disable play button and give feedback
- Say(TEXT("File failed to render!"));
- m_ButtonPlay.EnableWindow(FALSE);
- MessageBeep(0);
- return;
- }
- else
- {
- m_ButtonPlay.EnableWindow(TRUE);
- }
-
- // Display useful information about this file
- DisplayFileInfo(szFilename);
- DisplayImageInfo();
- DisplayFileDuration();
-
- // Set up the seeking trackbar and read capabilities
- ConfigureSeekbar();
-
- // Enumerate and display filters in graph
- hr = EnumFilters();
-
- // Select the first filter in the list to display pin info
- m_ListFilters.SetCurSel(0);
- OnSelchangeListFilters();
-
- // See if the renderer supports frame stepping on this file.
- // Enable/disable frame stepping button accordingly
- m_ButtonFrameStep.EnableWindow(CanStep());
-
- // If the user has asked to mute audio then we
- // need to mute this new clip before continuing.
- if (g_bGlobalMute)
- MuteAudio();
-
- // If we were running when the user changed selection,
- // start running the newly selected clip
- if (nCurrentState == State_Running)
- {
- OnPlay();
- }
- else
- {
- // Cue the first video frame
- OnStop();
- }
- }
-
-
- HRESULT CJukeboxDlg::PrepareMedia(LPTSTR lpszMovie)
- {
- USES_CONVERSION;
- HRESULT hr = S_OK;
-
- Say(TEXT("Loading..."));
-
- // Allow DirectShow to create the FilterGraph for this media file
- hr = pGB->RenderFile(T2W(lpszMovie), NULL);
- if (FAILED(hr)) {
- RetailOutput(TEXT("*** Failed(%08lx) in RenderFile(%s)!\r\n"),
- hr, lpszMovie);
- return hr;
- }
-
- // Set the message drain of the video window to point to our main
- // application window. If this is an audio-only or MIDI file,
- // then put_MessageDrain will fail.
- hr = pVW->put_MessageDrain((OAHWND) m_hWnd);
- if (FAILED(hr))
- {
- g_bAudioOnly = TRUE;
- }
-
- // Have the graph signal event via window callbacks
- hr = pME->SetNotifyWindow((OAHWND)m_hWnd, WM_GRAPHNOTIFY, 0);
-
- // Configure the video window
- if (!g_bAudioOnly)
- {
- // We'll manually set the video to be visible
- hr = pVW->put_Visible(OAFALSE);
-
- hr = pVW->put_WindowStyle(WS_CHILD);
- hr = pVW->put_Owner((OAHWND) m_Screen.GetSafeHwnd());
-
- // Place video window within the bounding rectangle
- CenterVideo();
-
- // Make the video window visible within the screen window.
- // If this is an audio-only file, then there won't be a video interface.
- hr = pVW->put_Visible(OATRUE);
- hr = pVW->SetWindowForeground(-1);
- }
-
- Say(TEXT("Ready"));
- return hr;
- }
-
-
- //
- // Displays a text string in a status line near the bottom of the dialog
- //
- void CJukeboxDlg::Say(LPTSTR szText)
- {
- m_Status.SetWindowText(szText);
- }
-
- void CJukeboxDlg::OnPause()
- {
- if (g_psCurrent == State_Paused)
- {
- RunMedia();
- StartSeekTimer();
- Say(TEXT("Running"));
- }
- else
- {
- StopSeekTimer();
- PauseMedia();
- Say(TEXT("PAUSED"));
- }
- }
-
- void CJukeboxDlg::OnPlay()
- {
- RunMedia();
- StartSeekTimer();
- Say(TEXT("Running"));
- }
-
- void CJukeboxDlg::ShowState()
- {
- HRESULT hr;
-
- OAFilterState fs;
- hr = pMC->GetState(500, &fs);
- if (FAILED(hr))
- {
- RetailOutput(TEXT("Failed to read graph state! hr=0x%x\r\n"), hr);
- return;
- }
-
- // Show debug output for current media state
- switch (fs)
- {
- case State_Stopped:
- RetailOutput(TEXT("State_Stopped\r\n"));
- break;
- case State_Paused:
- RetailOutput(TEXT("State_Paused\r\n"));
- break;
- case State_Running:
- RetailOutput(TEXT("State_Running\r\n"));
- break;
- }
- }
-
- void CJukeboxDlg::OnStop()
- {
- HRESULT hr;
-
- // Stop playback immediately with IMediaControl::Stop().
- StopSeekTimer();
- StopMedia();
-
- // Wait for the stop to propagate to all filters
- OAFilterState fs;
- hr = pMC->GetState(500, &fs);
- if (FAILED(hr))
- {
- RetailOutput(TEXT("Failed to read graph state! hr=0x%x\r\n"), hr);
- }
-
- // Reset to beginning of media clip
- LONGLONG pos=0;
- hr = pMS->SetPositions(&pos, AM_SEEKING_AbsolutePositioning ,
- NULL, AM_SEEKING_NoPositioning);
- if (FAILED(hr))
- {
- RetailOutput(TEXT("Failed to seek to beginning of media! hr=0x%x\r\n"), hr);
- }
-
- // Display the first frame of the media clip, if it contains video.
- // StopWhenReady() pauses all filters internally (which allows the video
- // renderer to queue and display the first video frame), after which
- // it sets the filters to the stopped state. This enables easy preview
- // of the video's poster frame.
- hr = pMC->StopWhenReady();
- if (FAILED(hr))
- {
- RetailOutput(TEXT("Failed in StopWhenReady! hr=0x%x\r\n"), hr);
- }
-
- Say(TEXT("Stopped"));
-
- // Reset slider bar and position label back to zero
- ReadMediaPosition();
- }
-
- HRESULT CJukeboxDlg::InitDirectShow(void)
- {
- HRESULT hr = S_OK;
-
- g_bAudioOnly = FALSE;
-
- // Zero interfaces (sanity check)
- pVW = NULL;
- pBV = NULL;
-
- JIF(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC, IID_IGraphBuilder, (void **)&pGB));
- JIF(pGB->QueryInterface(IID_IMediaControl, (void **)&pMC));
- JIF(pGB->QueryInterface(IID_IMediaSeeking, (void **)&pMS));
- JIF(pGB->QueryInterface(IID_IBasicVideo, (void **)&pBV));
- JIF(pGB->QueryInterface(IID_IVideoWindow, (void **)&pVW));
- JIF(pGB->QueryInterface(IID_IMediaEventEx, (void **)&pME));
-
- return S_OK;
-
- CLEANUP:
- FreeDirectShow();
- return(hr);
- }
-
- HRESULT CJukeboxDlg::FreeDirectShow(void)
- {
- HRESULT hr=S_OK;
-
- StopSeekTimer();
- StopMedia();
-
- // Disable event callbacks
- if (pME)
- hr = pME->SetNotifyWindow((OAHWND)NULL, 0, 0);
-
- // Hide video window and remove owner. This is not necessary here,
- // since we are about to destroy the filter graph, but it is included
- // for demonstration purposes. Remember to hide the video window and
- // clear its owner when destroying a window that plays video.
- if(pVW)
- {
- hr = pVW->put_Visible(OAFALSE);
- hr = pVW->put_Owner(NULL);
- }
-
- SAFE_RELEASE(pMC);
- SAFE_RELEASE(pMS);
- SAFE_RELEASE(pVW);
- SAFE_RELEASE(pBV);
- SAFE_RELEASE(pME);
- SAFE_RELEASE(pGB);
-
- return hr;
- }
-
- void CJukeboxDlg::ResetDirectShow(void)
- {
- // Destroy the current filter graph its filters.
- FreeDirectShow();
-
- // Reinitialize graph builder and query for interfaces
- InitDirectShow();
- }
-
- void CJukeboxDlg::CenterVideo(void)
- {
- LONG width, height;
- HRESULT hr;
-
- if ((g_bAudioOnly) || (!pVW))
- return;
-
- // Read coordinates of video container window
- RECT rc;
- m_Screen.GetClientRect(&rc);
- width = rc.right - rc.left;
- height = rc.bottom - rc.top;
-
- // Ignore the video's original size and stretch to fit bounding rectangle
- hr = pVW->SetWindowPosition(rc.left, rc.top, width, height);
- if (FAILED(hr))
- {
- RetailOutput(TEXT("Failed to set window position! hr=0x%x\r\n"), hr);
- return;
- }
- }
-
-
- LRESULT CJukeboxDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
- {
- // Field notifications from the DirectShow filter graph manager
- // and those posted by the application
- switch (message)
- {
- case WM_GRAPHNOTIFY:
- HandleGraphEvent();
- break;
-
- case WM_HSCROLL:
- HandleTrackbar(LOWORD(wParam));
- break;
-
- case WM_PLAYFILE:
- PlaySelectedFile();
- break;
-
- case WM_NEXTFILE:
- PlayNextFile();
- break;
-
- case WM_PREVIOUSFILE:
- PlayPreviousFile();
- break;
-
- case WM_FIRSTFILE:
- // Select the first item in the list
- m_ListFiles.SetCurSel(0);
- OnSelectFile();
- break;
-
- case WM_CLOSE:
- FreeDirectShow();
- break;
- }
-
- // Pass along this message to the video window, which exists as a child
- // of the m_Screen window. This method should be used by windows that
- // make a renderer window a child window. It forwards significant messages
- // to the child window that the child window would not otherwise receive.
- if (pVW)
- {
- pVW->NotifyOwnerMessage((LONG_PTR) m_hWnd, message, wParam, lParam);
- }
-
- return CDialog::WindowProc(message, wParam, lParam);
- }
-
-
- HRESULT CJukeboxDlg::HandleGraphEvent(void)
- {
- LONG evCode, evParam1, evParam2;
- HRESULT hr=S_OK;
-
- // Since we may have a scenario where we're shutting down the application,
- // but events are still being generated, make sure that the event
- // interface is still valid before using it. It's possible that
- // the interface could be freed during shutdown but later referenced in
- // this callback before the app completely exits.
- if (!pME)
- return S_OK;
-
- while(SUCCEEDED(pME->GetEvent(&evCode, (LONG_PTR *) &evParam1,
- (LONG_PTR *) &evParam2, 0)))
- {
- // Spin through the events
- hr = pME->FreeEventParams(evCode, evParam1, evParam2);
-
- if(EC_COMPLETE == evCode)
- {
- // If looping, reset to beginning and continue playing
- if (g_bLooping)
- {
- LONGLONG pos=0;
-
- // Reset to first frame of movie
- hr = pMS->SetPositions(&pos, AM_SEEKING_AbsolutePositioning ,
- NULL, AM_SEEKING_NoPositioning);
- if (FAILED(hr))
- {
- // Some custom filters (like the Windows CE MIDI filter)
- // may not implement seeking interfaces (IMediaSeeking)
- // to allow seeking to the start. In that case, just stop
- // and restart for the same effect. This should not be
- // necessary in most cases.
- StopMedia();
- RunMedia();
- }
- }
- else if (g_bPlayThrough)
- {
- // Tell the app to select the next file in the list
- PostMessage(WM_NEXTFILE, 0, 0);
- }
- else
- {
- // Stop playback and display first frame of movie
- OnStop();
- }
- }
-
- // If requested, display DirectShow events received
- if (g_bDisplayEvents)
- {
- DisplayECEvent(evCode, evParam1, evParam2);
- }
- }
-
- return hr;
- }
-
- void CJukeboxDlg::OnCheckMute()
- {
- // Remember global mute status for next file. When you destroy a
- // filtergraph, you lose all of its audio settings. Therefore, when
- // we create the next graph, we will mute the audio before running
- // the graph if this global variable is set.
- g_bGlobalMute ^= 1;
-
- if (g_bGlobalMute)
- MuteAudio();
- else
- ResumeAudio();
- }
-
- void CJukeboxDlg::OnCheckLoop()
- {
- g_bLooping ^= 1;
-
- // Looping and play-through are mutually exclusive
- if ((g_bLooping) && (g_bPlayThrough))
- {
- // Disable play-through and uncheck button
- g_bPlayThrough = 0;
- m_CheckPlaythrough.SetCheck(0);
- }
- }
-
- void CJukeboxDlg::OnCheckPlaythrough()
- {
- g_bPlayThrough ^= 1;
-
- // Looping and play-through are mutually exclusive
- if ((g_bPlayThrough) && (g_bLooping) )
- {
- // Disable play-through and uncheck button
- g_bLooping = 0;
- m_CheckLoop.SetCheck(0);
- }
- }
-
- void CJukeboxDlg::OnCheckEvents()
- {
- g_bDisplayEvents ^= 1;
- }
-
- void CJukeboxDlg::OnButtonClearEvents()
- {
- m_ListEvents.ResetContent();
- }
-
- void CJukeboxDlg::OnButtonSetMediadir()
- {
- TCHAR szEditPath[MAX_PATH];
- DWORD dwAttr;
-
- // Make sure that we're not playing media
- OnStop();
-
- // Read the string in the media directory edit box.
- m_EditMediaDir.GetWindowText(szEditPath, MAX_PATH);
-
- // Is this a valid directory name?
- dwAttr = GetFileAttributes(szEditPath);
- if ((dwAttr == (DWORD) -1) || (! (dwAttr & FILE_ATTRIBUTE_DIRECTORY)))
- {
- MessageBox(TEXT("Please enter a valid directory name."), TEXT("Media error"));
- return;
- }
-
- // User has specified a valid media directory.
- // Update the current path string.
- TCHAR szPathMsg[MAX_PATH];
- wsprintf(szPathMsg, TEXT("Media directory: %s\0"), szEditPath);
- m_StrMediaPath.SetWindowText(szPathMsg);
-
- // Save current directory name. Append the trailing '\' to match
- // the string created by GetDXSDKMediaPath() (if not present)
- int nLength = _tcslen(szEditPath);
- if (szEditPath[nLength - 1] != TEXT('\\'))
- wsprintf(m_szCurrentDir, TEXT("%s\\\0"), szEditPath);
-
- // Propagate the files list and select the first item
- FillFileList(szEditPath);
- }
-
-
- void CJukeboxDlg::OnDblclkListFiles()
- {
- // Because it might take time to render the file and display
- // its first frame, it's better to post a message that tells
- // the app to play the selected file when ready.
- PostMessage(WM_PLAYFILE, 0, 0L);
- }
-
- void CJukeboxDlg::PlaySelectedFile()
- {
- OnPlay();
- }
-
- void CJukeboxDlg::OnDeltaposSpinFiles(NMHDR* pNMHDR, LRESULT* pResult)
- {
- NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR;
-
- if (pNMUpDown->iDelta > 0)
- PostMessage(WM_NEXTFILE, 0, 0L);
- else
- PostMessage(WM_PREVIOUSFILE, 0, 0L);
-
- *pResult = 0;
- }
-
- void CJukeboxDlg::PlayNextFile(void)
- {
- int nItems = m_ListFiles.GetCount();
-
- // Return if the list is empty
- if (!nItems)
- return;
-
- int nCurSel = m_ListFiles.GetCurSel();
- int nNewSel = (nCurSel + 1) % nItems;
-
- // Select the next item in the list, wrapping to top if needed
- m_ListFiles.SetCurSel(nNewSel);
- OnSelectFile();
- }
-
-
- void CJukeboxDlg::PlayPreviousFile(void)
- {
- int nItems = m_ListFiles.GetCount();
-
- // Return if the list is empty
- if (!nItems)
- return;
-
- int nCurSel = m_ListFiles.GetCurSel();
- int nNewSel = nCurSel - 1;
-
- // If moved off top of list, select last item in list
- if (nNewSel < 0)
- nNewSel = nItems - 1;
-
- // Select the next item in the list, wrapping to top if needed
- m_ListFiles.SetCurSel(nNewSel);
- OnSelectFile();
- }
-
-
- HRESULT CJukeboxDlg::EnumFilters (void)
- {
- HRESULT hr;
- IEnumFilters *pEnum = NULL;
- IBaseFilter *pFilter = NULL;
- ULONG cFetched;
-
- // Clear filters list box
- m_ListFilters.ResetContent();
-
- // Get filter enumerator
- hr = pGB->EnumFilters(&pEnum);
- if (FAILED(hr))
- {
- m_ListFilters.AddString(TEXT("<ERROR>"));
- return hr;
- }
-
- // Enumerate all filters in the graph
- while(pEnum->Next(1, &pFilter, &cFetched) == S_OK)
- {
- FILTER_INFO FilterInfo;
- TCHAR szName[256];
-
- hr = pFilter->QueryFilterInfo(&FilterInfo);
- if (FAILED(hr))
- {
- m_ListFilters.AddString(TEXT("<ERROR>"));
- }
- else
- {
- // Add the filter name to the filters listbox
- USES_CONVERSION;
-
- lstrcpy(szName, W2T(FilterInfo.achName));
- m_ListFilters.AddString(szName);
-
- FilterInfo.pGraph->Release();
- }
- pFilter->Release();
- }
- pEnum->Release();
-
- return hr;
- }
-
-
- //
- // The GraphBuilder interface provides a FindFilterByName() method,
- // which provides similar functionality to the method below.
- // This local method is provided for educational purposes.
- //
- IBaseFilter *CJukeboxDlg::FindFilterFromName(LPTSTR szNameToFind)
- {
- USES_CONVERSION;
-
- HRESULT hr;
- IEnumFilters *pEnum = NULL;
- IBaseFilter *pFilter = NULL;
- ULONG cFetched;
- BOOL bFound = FALSE;
-
- // Get filter enumerator
- hr = pGB->EnumFilters(&pEnum);
- if (FAILED(hr))
- return NULL;
-
- // Enumerate all filters in the graph
- while((pEnum->Next(1, &pFilter, &cFetched) == S_OK) && (!bFound))
- {
- FILTER_INFO FilterInfo;
- TCHAR szName[256];
-
- hr = pFilter->QueryFilterInfo(&FilterInfo);
- if (FAILED(hr))
- {
- pFilter->Release();
- pEnum->Release();
- return NULL;
- }
-
- // Compare this filter's name with the one we want
- lstrcpy(szName, W2T(FilterInfo.achName));
- if (! lstrcmp(szName, szNameToFind))
- {
- bFound = TRUE;
- }
-
- FilterInfo.pGraph->Release();
-
- // If we found the right filter, don't release its interface.
- // The caller will use it and release it later.
- if (!bFound)
- pFilter->Release();
- else
- break;
- }
- pEnum->Release();
-
- return (bFound ? pFilter : NULL);
- }
-
-
- HRESULT CJukeboxDlg::EnumPins(IBaseFilter *pFilter, PIN_DIRECTION PinDir,
- CListBox& Listbox)
- {
- HRESULT hr;
- IEnumPins *pEnum = NULL;
- IPin *pPin = NULL;
-
- // Clear the specified listbox (input or output)
- Listbox.ResetContent();
-
- // Get pin enumerator
- hr = pFilter->EnumPins(&pEnum);
- if (FAILED(hr))
- {
- Listbox.AddString(TEXT("<ERROR>"));
- return hr;
- }
-
- // Enumerate all pins on this filter
- while(pEnum->Next(1, &pPin, 0) == S_OK)
- {
- PIN_DIRECTION PinDirThis;
-
- hr = pPin->QueryDirection(&PinDirThis);
- if (FAILED(hr))
- {
- Listbox.AddString(TEXT("<ERROR>"));
- pPin->Release();
- continue;
- }
-
- // Does the pin's direction match the requested direction?
- if (PinDir == PinDirThis)
- {
- PIN_INFO pininfo={0};
-
- // Direction matches, so add pin name to listbox
- hr = pPin->QueryPinInfo(&pininfo);
- if (SUCCEEDED(hr))
- {
- CString str(pininfo.achName);
- Listbox.AddString(str);
- }
-
- // The pininfo structure contains a reference to an IBaseFilter,
- // so you must release its reference to prevent resource a leak.
- pininfo.pFilter->Release();
- }
- pPin->Release();
- }
- pEnum->Release();
-
- return hr;
- }
-
-
- void CJukeboxDlg::OnSelchangeListFilters()
- {
- HRESULT hr;
- IBaseFilter *pFilter = NULL;
- TCHAR szNameToFind[128];
-
- // Read the current filter name from the list box
- int nCurSel = m_ListFilters.GetCurSel();
- m_ListFilters.GetText(nCurSel, szNameToFind);
-
- // Read the current list box name and find it in the graph
- pFilter = FindFilterFromName(szNameToFind);
- if (!pFilter)
- return;
-
- // Now that we have filter information, enumerate pins by direction
- // and add their names to the appropriate listboxes
- hr = EnumPins(pFilter, PINDIR_INPUT, m_ListPinsInput);
- hr = EnumPins(pFilter, PINDIR_OUTPUT, m_ListPinsOutput);
-
- // Find out if this filter supports a property page
- if (SupportsPropertyPage(pFilter))
- m_ButtonProperties.EnableWindow(TRUE);
- else
- m_ButtonProperties.EnableWindow(FALSE);
-
- // Must release the filter interface returned from FindFilterByName()
- pFilter->Release();
- }
-
-
- BOOL CJukeboxDlg::DisplayImageInfo(void)
- {
- HRESULT hr;
- long lWidth, lHeight;
-
- // If this file has no video component, clear the text field
- if ((!pBV) || (g_bAudioOnly))
- {
- m_StrImageSize.SetWindowText(TEXT("\0"));
- return FALSE;
- }
-
- hr = pBV->GetVideoSize(&lWidth, &lHeight);
- if (SUCCEEDED(hr))
- {
- TCHAR szSize[64];
- wsprintf(szSize, TEXT("Image size: %d x %d\0"), lWidth, lHeight);
- m_StrImageSize.SetWindowText(szSize);
- }
-
- return TRUE;
- }
-
-
- BOOL CJukeboxDlg::DisplayFileInfo(LPTSTR szFile)
- {
- HANDLE hFile;
- LONGLONG llSize=0;
- DWORD dwSizeLow=0, dwSizeHigh=0;
- TCHAR szScrap[64];
-
- // Open the specified file to read size and date information
- hFile = CreateFile(szFile,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,
- (DWORD) 0, NULL);
-
- if (hFile == INVALID_HANDLE_VALUE)
- {
- RetailOutput(TEXT("*** Failed(0x%x) to open file (to read size)!\r\n"),
- GetLastError());
- return FALSE;
- }
-
- dwSizeLow = GetFileSize(hFile, &dwSizeHigh);
- if ((dwSizeLow == 0xFFFFFFFF) && (GetLastError() != NO_ERROR))
- {
- RetailOutput(TEXT("*** Error(0x%x) reading file size!\r\n"),
- GetLastError());
- CloseHandle(hFile);
- return FALSE;
- }
-
- // Large files will also use the upper DWORD to report size.
- // Add them together for the true size if necessary.
- if (dwSizeHigh)
- llSize = (dwSizeHigh << 16) + dwSizeLow;
- else
- llSize = dwSizeLow;
-
- // Read date information
- BY_HANDLE_FILE_INFORMATION fi;
- if (GetFileInformationByHandle(hFile, &fi))
- {
- CTime time(fi.ftLastWriteTime);
-
- wsprintf(szScrap, TEXT("File date: %02d/%02d/%d\0"),
- time.GetMonth(), time.GetDay(), time.GetYear());
- m_StrFileDate.SetWindowText(szScrap);
- }
-
- CloseHandle(hFile);
-
- // Update size/date windows
- wsprintf(szScrap, TEXT("Size: %d bytes\0"), dwSizeLow);
- m_StrFileSize.SetWindowText(szScrap);
-
- return TRUE;
- }
-
-
- HRESULT CJukeboxDlg::DisplayFileDuration(void)
- {
- HRESULT hr;
-
- if (!pMS)
- return E_NOINTERFACE;
-
- // Initialize the display in case we can't read the duration
- m_StrDuration.SetWindowText(TEXT("<00:00.000>"));
-
- // Is media time supported for this file?
- if (S_OK != pMS->IsFormatSupported(&TIME_FORMAT_MEDIA_TIME))
- return E_NOINTERFACE;
-
- // Read the time format to restore later
- GUID guidOriginalFormat;
- hr = pMS->GetTimeFormat(&guidOriginalFormat);
- if (FAILED(hr))
- return hr;
-
- // Ensure media time format for easy display
- hr = pMS->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME);
- if (FAILED(hr))
- return hr;
-
- // Read the file's duration
- LONGLONG llDuration;
- hr = pMS->GetDuration(&llDuration);
- if (FAILED(hr))
- return hr;
-
- // Return to the original format
- if (guidOriginalFormat != TIME_FORMAT_MEDIA_TIME)
- {
- hr = pMS->SetTimeFormat(&guidOriginalFormat);
- if (FAILED(hr))
- return hr;
- }
-
- // Convert the LONGLONG duration into human-readable format
- unsigned long nTotalMS = (unsigned long) llDuration / 10000; // 100ns -> ms
- int nMS = nTotalMS % 1000;
- int nSeconds = nTotalMS / 1000;
- int nMinutes = nSeconds / 60;
- nSeconds %= 60;
-
- // Update the display
- TCHAR szDuration[24];
- wsprintf(szDuration, _T("%02dm:%02d.%03ds\0"), nMinutes, nSeconds, nMS);
- m_StrDuration.SetWindowText(szDuration);
-
- return hr;
- }
-
-
- BOOL CJukeboxDlg::SupportsPropertyPage(IBaseFilter *pFilter)
- {
- HRESULT hr;
- ISpecifyPropertyPages *pSpecify;
-
- // Discover if this filter contains a property page
- hr = pFilter->QueryInterface(IID_ISpecifyPropertyPages, (void **)&pSpecify);
- if (SUCCEEDED(hr))
- {
- pSpecify->Release();
- return TRUE;
- }
- else
- return FALSE;
- }
-
- void CJukeboxDlg::OnButtonProppage()
- {
- HRESULT hr;
- IBaseFilter *pFilter = NULL;
- TCHAR szNameToFind[128];
- ISpecifyPropertyPages *pSpecify;
-
- // Read the current filter name from the list box
- int nCurSel = m_ListFilters.GetCurSel();
- m_ListFilters.GetText(nCurSel, szNameToFind);
-
- // Read the current list box name and find it in the graph
- pFilter = FindFilterFromName(szNameToFind);
- if (!pFilter)
- return;
-
- // Discover if this filter contains a property page
- hr = pFilter->QueryInterface(IID_ISpecifyPropertyPages, (void **)&pSpecify);
- if (SUCCEEDED(hr))
- {
- do
- {
- FILTER_INFO FilterInfo;
- hr = pFilter->QueryFilterInfo(&FilterInfo);
- if (FAILED(hr))
- break;
-
- CAUUID caGUID;
- hr = pSpecify->GetPages(&caGUID);
- if (FAILED(hr))
- break;
-
- pSpecify->Release();
-
- // Display the filter's property page
- OleCreatePropertyFrame(
- m_hWnd, // Parent window
- 0, // x (Reserved)
- 0, // y (Reserved)
- FilterInfo.achName, // Caption for the dialog box
- 1, // Number of filters
- (IUnknown **)&pFilter, // Pointer to the filter
- caGUID.cElems, // Number of property pages
- caGUID.pElems, // Pointer to property page CLSIDs
- 0, // Locale identifier
- 0, // Reserved
- NULL // Reserved
- );
- CoTaskMemFree(caGUID.pElems);
- FilterInfo.pGraph->Release();
-
- } while(0);
- }
-
- pFilter->Release();
- }
-
- void CJukeboxDlg::OnDblclkListFilters()
- {
- OnButtonProppage();
- }
-
-
- void CJukeboxDlg::DisplayECEvent(long lEventCode, long lParam1, long lParam2)
- {
- static TCHAR szMsg[256];
- BOOL bMatch = TRUE;
-
- #define HANDLE_EC(c) \
- case c: \
- wsprintf(szMsg, TEXT("%s\0"), TEXT(#c)); \
- break;
-
- switch (lEventCode)
- {
- HANDLE_EC(EC_ACTIVATE);
- HANDLE_EC(EC_BUFFERING_DATA);
- HANDLE_EC(EC_CLOCK_CHANGED);
- HANDLE_EC(EC_COMPLETE);
- HANDLE_EC(EC_DEVICE_LOST);
- HANDLE_EC(EC_DISPLAY_CHANGED);
- HANDLE_EC(EC_END_OF_SEGMENT);
- HANDLE_EC(EC_ERROR_STILLPLAYING);
- HANDLE_EC(EC_ERRORABORT);
- HANDLE_EC(EC_EXTDEVICE_MODE_CHANGE);
- HANDLE_EC(EC_FULLSCREEN_LOST);
- HANDLE_EC(EC_GRAPH_CHANGED);
- HANDLE_EC(EC_LENGTH_CHANGED);
- HANDLE_EC(EC_NEED_RESTART);
- HANDLE_EC(EC_NOTIFY_WINDOW);
- HANDLE_EC(EC_OLE_EVENT);
- HANDLE_EC(EC_OPENING_FILE);
- HANDLE_EC(EC_PALETTE_CHANGED);
- HANDLE_EC(EC_PAUSED);
- HANDLE_EC(EC_QUALITY_CHANGE);
- HANDLE_EC(EC_REPAINT);
- HANDLE_EC(EC_SEGMENT_STARTED);
- HANDLE_EC(EC_SHUTTING_DOWN);
- HANDLE_EC(EC_SNDDEV_IN_ERROR);
- HANDLE_EC(EC_SNDDEV_OUT_ERROR);
- HANDLE_EC(EC_STARVATION);
- HANDLE_EC(EC_STEP_COMPLETE);
- HANDLE_EC(EC_STREAM_CONTROL_STARTED);
- HANDLE_EC(EC_STREAM_CONTROL_STOPPED);
- HANDLE_EC(EC_STREAM_ERROR_STILLPLAYING);
- HANDLE_EC(EC_STREAM_ERROR_STOPPED);
- HANDLE_EC(EC_TIMECODE_AVAILABLE);
- HANDLE_EC(EC_USERABORT);
- HANDLE_EC(EC_VIDEO_SIZE_CHANGED);
- HANDLE_EC(EC_WINDOW_DESTROYED);
-
- default:
- bMatch = FALSE;
- RetailOutput(TEXT(" Received unknown event code (0x%x)\r\n"), lEventCode);
- break;
- }
-
- // If a recognized event was found, add its name to the events list box
- if (bMatch)
- m_ListEvents.AddString(szMsg);
- }
-
-
- void CJukeboxDlg::OnButtonFramestep()
- {
- StepFrame();
- }
-
-
- //
- // Some hardware decoders and video renderers support stepping media
- // frame by frame with the IVideoFrameStep interface. See the interface
- // documentation for more details on frame stepping.
- //
- BOOL CJukeboxDlg::CanStep(void)
- {
- HRESULT hr;
- IVideoFrameStep* pFS;
-
- hr = pGB->QueryInterface(__uuidof(IVideoFrameStep), (PVOID *)&pFS);
- if (FAILED(hr))
- return FALSE;
-
- // Check if this decoder can step
- hr = pFS->CanStep(0L, NULL);
-
- pFS->Release();
-
- if (hr == S_OK)
- return TRUE;
- else
- return FALSE;
- }
-
- HRESULT CJukeboxDlg::StepFrame(void)
- {
- // Get the Frame Stepping Interface
- HRESULT hr;
- IVideoFrameStep* pFS;
-
- hr = pGB->QueryInterface(__uuidof(IVideoFrameStep), (PVOID *)&pFS);
- if (FAILED(hr))
- return hr;
-
- // The graph must be paused for frame stepping to work
- if (g_psCurrent != State_Paused)
- OnPause();
-
- // Step one frame
- hr = pFS->Step(1, NULL);
- pFS->Release();
-
- // Since the media position has changed slightly, update the
- // slider bar and position label.
- ReadMediaPosition();
- return hr;
- }
-
-
- void CJukeboxDlg::ConfigureSeekbar()
- {
- // Disable seekbar for new file and reset tracker/position label
- m_Seekbar.SetPos(0);
- m_StrPosition.SetWindowText(TEXT("Position: 00m:00s\0"));
- g_rtTotalTime=0;
-
- // If we can't read the file's duration, disable the seek bar
- if (pMS && SUCCEEDED(pMS->GetDuration(&g_rtTotalTime)))
- m_Seekbar.EnableWindow(TRUE);
- else
- m_Seekbar.EnableWindow(FALSE);
- }
-
- void CJukeboxDlg::StartSeekTimer()
- {
- // Cancel any pending timer event
- StopSeekTimer();
-
- // Create a new timer
- g_wTimerID = SetTimer(TIMERID, TICKLEN, NULL);
- }
-
- void CJukeboxDlg::StopSeekTimer()
- {
- // Cancel the timer
- if(g_wTimerID)
- {
- KillTimer(g_wTimerID);
- g_wTimerID = 0;
- }
- }
-
- void CJukeboxDlg::OnTimer(UINT nIDEvent)
- {
- ReadMediaPosition();
-
- CDialog::OnTimer(nIDEvent);
- }
-
- void CJukeboxDlg::ReadMediaPosition()
- {
- HRESULT hr;
- REFERENCE_TIME rtNow;
-
- // Read the current stream position
- hr = pMS->GetCurrentPosition(&rtNow);
- if (FAILED(hr))
- return;
-
- // Convert position into a percentage value and update slider position
- if (g_rtTotalTime != 0)
- {
- long lTick = (long)((rtNow * 100) / g_rtTotalTime);
- m_Seekbar.SetPos(lTick);
- }
- else
- m_Seekbar.SetPos(0);
-
- // Update the 'current position' string on the main dialog
- UpdatePosition(rtNow);
- }
-
- void CJukeboxDlg::UpdatePosition(REFERENCE_TIME rtNow)
- {
- HRESULT hr;
-
- // If no reference time was passed in, read the current position
- if (rtNow == 0)
- {
- // Read the current stream position
- hr = pMS->GetCurrentPosition(&rtNow);
- if (FAILED(hr))
- return;
- }
-
- // Convert the LONGLONG duration into human-readable format
- unsigned long nTotalMS = (unsigned long) rtNow / 10000; // 100ns -> ms
- int nSeconds = nTotalMS / 1000;
- int nMinutes = nSeconds / 60;
- nSeconds %= 60;
-
- // Update the display
- TCHAR szPosition[24], szCurrentString[24];
- wsprintf(szPosition, _T("Position: %02dm:%02ds\0"), nMinutes, nSeconds);
-
- // Read current string and compare to the new string. To prevent flicker,
- // don't update this label unless the string has changed.
- m_StrPosition.GetWindowText(szCurrentString, 24);
-
- if (_tcscmp(szCurrentString, szPosition))
- m_StrPosition.SetWindowText(szPosition);
- }
-
- void CJukeboxDlg::HandleTrackbar(WPARAM wReq)
- {
- HRESULT hr;
- static OAFilterState state;
- static BOOL bStartOfScroll = TRUE;
-
- // If the file is not seekable, the trackbar is disabled.
- DWORD dwPosition = m_Seekbar.GetPos();
-
- // Pause when the scroll action begins.
- if (bStartOfScroll)
- {
- hr = pMC->GetState(10, &state);
- bStartOfScroll = FALSE;
- hr = pMC->Pause();
- }
-
- // Update the position continuously.
- REFERENCE_TIME rtNew = (g_rtTotalTime * dwPosition) / 100;
-
- hr = pMS->SetPositions(&rtNew, AM_SEEKING_AbsolutePositioning,
- NULL, AM_SEEKING_NoPositioning);
-
- // Restore the state at the end.
- if (wReq == TB_ENDTRACK)
- {
- if (state == State_Stopped)
- hr = pMC->Stop();
- else if (state == State_Running)
- hr = pMC->Run();
-
- bStartOfScroll = TRUE;
- }
-
- // Update the 'current position' string on the main dialog.
- UpdatePosition(rtNew);
- }
-
- LONG CJukeboxDlg::GetGraphEditPath(TCHAR *szPath)
- {
- HKEY hKey;
- DWORD dwType, dwSize = MAX_PATH;
-
- // Open the appropriate registry key
- LONG lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
- _T("Software\\Microsoft\\Shared Tools\\Graphedit"),
- 0, KEY_READ, &hKey );
- if( ERROR_SUCCESS != lResult )
- return -1;
-
- // Read the full path (including .exe name) for the GraphEdit tool
- lResult = RegQueryValueEx( hKey, _T("Path"), NULL,
- &dwType, (BYTE*)szPath, &dwSize );
- RegCloseKey( hKey );
-
- if( ERROR_SUCCESS != lResult )
- return -1;
-
- return 0;
- }
-
- void CJukeboxDlg::OnButtonGraphedit()
- {
- TCHAR szFilename[128], szFile[MAX_PATH];
-
- // Read file name from list box
- int nItem = m_ListFiles.GetCurSel();
- m_ListFiles.GetText(nItem, szFilename);
-
- // Build the full file name with path. The path will already have
- // a '\' appended to the end.
- wsprintf(szFile, TEXT("%s%s\0"), m_szCurrentDir, szFilename);
-
- // Launch GraphEdit for the selected file
- //
- // First look for a registry key containing its full path
- TCHAR szPath[MAX_PATH];
-
- LONG lResult = GetGraphEditPath(szPath);
-
- // If the DirectX SDK is not installed, just look for GraphEdit
- // anywhere in the system path.
- if (lResult != 0)
- {
- wsprintf(szPath, TEXT("%s\0"), TEXT("graphedt\0"));
- }
-
- // Lauch GraphEdit using either the full tool path or just its name
- HINSTANCE rc = ShellExecute(m_hWnd, TEXT("open\0"), szPath,
- szFile, NULL, SW_SHOWNORMAL);
-
- if (rc < (HINSTANCE) 32)
- {
- // Failed to start the app
- if ((rc == (HINSTANCE) ERROR_FILE_NOT_FOUND) ||
- (rc == (HINSTANCE) ERROR_PATH_NOT_FOUND))
- {
- MessageBox(TEXT("Couldn't find the GraphEdit application.\r\n\r\n")
- TEXT("Please copy graphedt.exe to a directory on your path."),
- TEXT("Can't find GraphEdit"));
- }
- }
- }
-
- BOOL CJukeboxDlg::OnEraseBkgnd(CDC *pDC)
- {
- // Intercept background erasing for the movie window, since the
- // video renderer will keep the screen painted. Without this code,
- // your video window might get painted over with gray (the default
- // background brush) when it is obscured by another window and redrawn.
- CRect rc;
-
- // Get the bounding rectangle for the movie screen
- m_Screen.GetWindowRect(&rc);
- ScreenToClient(&rc);
-
- // Exclude the clipping region occupied by our movie screen
- pDC->ExcludeClipRect(&rc);
-
- // Erase the remainder of the dialog as usual
- return CDialog::OnEraseBkgnd(pDC);
- }
-